/* Copyright 2012-2013 University of Stavanger, Norway Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package no.maddin.niofs.webdav; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.channels.SeekableByteChannel; import java.nio.file.AccessMode; import java.nio.file.CopyOption; import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream.Filter; import java.nio.file.FileStore; import java.nio.file.FileSystem; import java.nio.file.FileSystemException; import java.nio.file.FileSystemNotFoundException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.NoSuchFileException; import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.ProviderMismatchException; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileAttributeView; import java.nio.file.spi.FileSystemProvider; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import com.github.sardine.DavResource; import com.github.sardine.Sardine; import com.github.sardine.impl.SardineException; /** * The WebDAV FileSystemProvider based on Sardine. */ public class WebdavFileSystemProvider extends FileSystemProvider { private static final int DEFAULT_PORT = 80; private final Map<URI, WebdavFileSystem> hosts = new HashMap<>(); @Override public void copy(Path fileFrom, Path fileTo, CopyOption... options) throws IOException { if (!(fileFrom instanceof WebdavPath)) { throw new IllegalArgumentException(fileFrom.toString()); } if (!(fileTo instanceof WebdavPath)) { throw new IllegalArgumentException(fileTo.toString()); } WebdavPath wPathTo = (WebdavPath)fileTo; WebdavFileSystem webdavHost = (WebdavFileSystem)fileTo.getFileSystem(); Sardine webdav = webdavHost.getSardine(); webdav.put(wPathTo.toUri().toString(), Files.readAllBytes(fileFrom)); } @Override public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException { if (!(dir instanceof WebdavPath)) { throw new IllegalArgumentException(dir.toString()); } WebdavPath wDir = (WebdavPath)dir; WebdavFileSystem webdavHost = (WebdavFileSystem)dir.getFileSystem(); Sardine webdav = webdavHost.getSardine(); createDirectoryRecursive(webdav, wDir, attrs); } private void createDirectoryRecursive(Sardine webdav, WebdavPath wDir, FileAttribute<?>[] attrs) throws IOException { if (webdav.exists(wDir.toUri().toString())) { return; } WebdavPath parent = (WebdavPath)wDir.getParent(); if (parent != null) { createDirectoryRecursive(webdav, parent, attrs); } webdav.createDirectory(wDir.toUri().toString()); } @Override public void delete(Path dir) throws IOException { if (!(dir instanceof WebdavPath)) { throw new IllegalArgumentException(dir.toString()); } WebdavPath wDir = (WebdavPath)dir; WebdavFileSystem webdavHost = (WebdavFileSystem)dir.getFileSystem(); Sardine webdav = webdavHost.getSardine(); String dirString = ""; try { dirString = wDir.toUri().toString(); webdav.delete(dirString); } catch(SardineException se) { if (se.getCause() instanceof IOException) { throw (IOException)se.getCause(); } if (Objects.equals(se.getResponsePhrase(), "Not Found")) { throw new NoSuchFileException(dirString); } throw new IOException(se); } } /** * The default implementation in FileSystemProvider will simply call * delete() in deleteIfExists() and silently ignore any NoSuchFileException. * In case of Nexus, trying to delete() will result in 503 (Not allowed) * even if the path points to nowhere. */ @Override public boolean deleteIfExists(Path path) throws IOException { WebdavFileSystem webdavFs = (WebdavFileSystem)path.getFileSystem(); final String s = path.toUri().toString(); return webdavFs.getSardine().exists(s); } @Override public FileSystem getFileSystem(URI uri) { try { return getWebdavHost(uri, true); } catch(URISyntaxException ex) { throw new FileSystemNotFoundException(uri.toString()); } } @Override public Path getPath(URI uri) { try { WebdavFileSystem host = getWebdavHost(uri, true); return new WebdavPath(host, uri.getPath()); } catch(URISyntaxException e) { throw new FileSystemNotFoundException(uri.toString()); } } private WebdavFileSystem getWebdavHost(URI uri, boolean create) throws URISyntaxException { String host = uri.getHost(); int port = uri.getPort(); if (port == -1) { port = DEFAULT_PORT; } String userInfo = uri.getUserInfo(); URI serverUri = new URI(getScheme(), userInfo, host, port, null, null, null); synchronized (hosts) { WebdavFileSystem fs = hosts.get(serverUri); if (fs == null && create) { fs = new WebdavFileSystem(this, serverUri); hosts.put(serverUri, fs); } return fs; } } @Override public String getScheme() { return "webdav"; } /** * Unsupported */ @Override public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options) { throw new UnsupportedOperationException(); } /** * Unsupported */ @Override public FileStore getFileStore(Path path) throws IOException { throw new UnsupportedOperationException(); } @Override public void checkAccess(Path path, AccessMode... modes) throws IOException { WebdavFileSystem webdavFs = (WebdavFileSystem)path.getFileSystem(); final String s = path.toUri().toString(); final boolean exists = webdavFs.getSardine().exists(s); if (!exists) { throw new NoSuchFileException(s); } } /** * Unsupported */ @Override public boolean isHidden(Path path) throws IOException { throw new UnsupportedOperationException(); } /** * Unsupported */ @Override public boolean isSameFile(Path path, Path path2) throws IOException { throw new UnsupportedOperationException(); } /** * Unsupported */ @Override public void move(Path source, Path target, CopyOption... options) throws IOException { throw new UnsupportedOperationException(); } @Override public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException { return new SardineChannel((WebdavPath)path); } /** * Unsupported */ @Override public DirectoryStream<Path> newDirectoryStream(Path arg0, Filter<? super Path> arg1) throws IOException { throw new UnsupportedOperationException(); } @Override public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException { try { return getWebdavHost(uri, true); } catch(URISyntaxException e) { throw new FileSystemException(e.toString()); } } @SuppressWarnings("unchecked") @Override public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options) throws IOException { WebdavFileSystem wfs = (WebdavFileSystem)path.getFileSystem(); List<DavResource> resources = wfs.getSardine().list(path.toUri().toString()); if (resources.size() != 1) { throw new IllegalArgumentException(); } final DavResource res = resources.get(0); if (!type.isAssignableFrom(WebdavFileAttributes.class)) { throw new ProviderMismatchException(); } return (A)new WebdavFileAttributes(res); } /** * Unsupported */ @Override public Map<String, Object> readAttributes(Path arg0, String arg1, LinkOption... arg2) throws IOException { throw new UnsupportedOperationException(); } /** * Unsupported */ @Override public void setAttribute(Path arg0, String arg1, Object arg2, LinkOption... arg3) throws IOException { throw new UnsupportedOperationException(); } }